/*********************************************************
*
*  FJH-sim v1.0
*  Copyright � 2008 J.H. Donker, J. Teeuw
*
*  Simulator stress-testing driver
*
**********************************************************/

#include "simulator/StressDriver.h"
#include <iostream>
#include <math.h>

#include <node/SimNode.h>
#include <protocol/SimulatorProtocolStack.h>
#include <protocol/NetworkLayer.h>


std::string randomString(unsigned int length)
{
	std::string result;
	for(unsigned int i=0; i < length; i++)
	{
		char c = (char)simulator::dice(57) + 65;
		result += c;
		
	}
	return result;
}

using namespace simulator;
#define PI 3.1415926535897932f
#include <math.h>
void worldCircle(Simulator * sim, int nodes) {
	if (nodes < 3)
		nodes = 3;
	//creates a world with all the nodes in a circle,
	//where the radius is just large enough so each nodes
	//has only two neightbours in its range
	float range = sim->getRange() - 0.1f;
	float degrees = 360.0f/nodes;
	
	//radius: sinusregel.
	//angle known, one side known. Other two sides are equal and the two other angles aswell (180 in total).
	float radius = (range/degrees) * ((180.0f-degrees)/2.0f);
	
	float phi = 0.0f;
	for(int i = 0; i < nodes; i++) {
		float x = radius*cos(phi);
		float y = radius*sin(phi);
		EventNode* n = new EventNode(x, y, 0, sim);
		sim->addNode(n);
		phi += degrees;
	}
}

void worldGrid(Simulator * sim, int nodes) {
	float range = sim->getRange() - 0.1f;
	int lineSize = (int)sqrt((float)nodes);
	
	//Place various nodes in unifor grid
	for(int i = 0; i < nodes; i++) {
		float xPos = (range) * (float)(i%lineSize);
		float yPos = (range) * (float)(i/lineSize);
		simulator::EventNode* n = new simulator::EventNode(xPos, yPos, 0, sim);
		sim->addNode(n);
	}
}

void worldRandomGrid(Simulator * sim, int nodes) {
	float range = sim->getRange() - 0.1f;
	float distance = (sqrt(nodes)*range);
	
	//Place various nodes at random locations. Distribute of field of size distance x distance,	[0,distance] range
	for(int i = 0; i < nodes; i++) {
		float xPos = (float) (rand()/(float)RAND_MAX) * distance;
		float yPos = (float) (rand()/(float)RAND_MAX) * distance;
		EventNode* n = new EventNode(xPos, yPos, 0, sim);
		sim->addNode(n);
	}
}

void worldLine(Simulator * sim, int nodes) {
	float range = sim->getRange() - 0.1f;
	
	float xPos = 0.0f;
	for(int i = 0; i < nodes; i++) {
		EventNode* n = new EventNode(xPos, 0, 0, sim);
		sim->addNode(n);
		xPos += range;
	}
}

void StressDriver::createWorld()
{
	using namespace std;
	cout << "Driver creating world" << endl;
	switch(worldType) {
		case 0:
			worldCircle(sim, nrNodes);
			break;
		case 1:
			worldGrid(sim, nrNodes);
			break;
		case 2:
			worldRandomGrid(sim, nrNodes);
			break;
		case 3:
		default:
			worldLine(sim, nrNodes);
			break;
	}
	return;

/*
	simulator::EventNode* n0 = new simulator::EventNode(0, 0, 0, sim);
	simulator::EventNode* n1 = new simulator::EventNode(10, 0, 0, sim);
	simulator::EventNode* n2 = new simulator::EventNode(10,10, 0, sim);
	simulator::EventNode* n3 = new simulator::EventNode(0, 10, 0, sim);
	simulator::EventNode* n4 = new simulator::EventNode(201, 20, 120, sim);
	simulator::EventNode* n5 = new simulator::EventNode(20, 201, 120, sim);

	sim->addNode(n0);
	sim->addNode(n1);
	sim->addNode(n2);
	sim->addNode(n3);
	sim->addNode(n4);
	sim->addNode(n5);
*/
}

void StressDriver::run(int times) {
	Driver::run(times);
	printStat();
}

void StressDriver::sendDrive()
{
	if (sim->getTicks() > 950)	//50 ticks to finish everything off
		return;
	using namespace std;
	using namespace simulator;
	size_t nrStacks = sim->getNumberOfStacks();
	for(unsigned int i=0; i < nrStacks; i++)
	{
		std::vector<unsigned int> list;
		sim->getProtocolStack(i)->getAcquaintances(list);
		sim->getProtocolStack(i)->getFriends(list);

		/*unsigned int target = dice(nrStacks);
		if (target == i) {
			target = (target+1)%nrStacks;
		}*/
		unsigned int size = list.size();
		if (size > 0)
		{
			unsigned int selector = dice(size);
			unsigned int target = list[selector];
			
			//cout << "sending" << endl;
			if (!sim->getProtocolStack(i)->select(REQUEST_READY_SEND, &target))
			{
				//cout << "cannot send data, stack busy" << endl;
			}
			else
			{
				//string s = randomString(simulator::dice(20) + 80);	//use long strings
				char buffer[255];
				sprintf(buffer, "Sending from %u to %u: hi", i, target);
				//cout << "sending to " << target << ": " << buffer << endl;
				messagesSent++;
				//sim->getProtocolStack(i)->send(s.data(), s.length(), (NodeAddress)target);
				int res = sim->getProtocolStack(i)->send(buffer, strlen(buffer), (NodeAddress)target);
				if (res == -1) {
					error_print("StressDriver", "Send failure!");
				}
			}
		}
	}
}

void StressDriver::receiveDrive()
{
	using namespace std;
	char buffer[4096];
	bzero(&buffer, 4096);
	for(unsigned int i= 0; i < sim->getNumberOfStacks(); i++)
	{
		while(sim->getProtocolStack(i)->select(REQUEST_READY_RECEIVE, NULL)) 
		{
			NodeAddress source;
			int val = sim->getProtocolStack(i)->receive(buffer, 4096, source);
			if (val == -1)
				break;
			buffer[val] = 0;
			//cout << "receiving data from " << source << ": " << buffer << endl;
			messagesReceived++;
		}
	}
}

void StressDriver::waitForContinue() 
{
	using namespace std;
	//printStat();
	//std::cin.get();
	cout << "Tick: " << sim->getTicks() << endl;
}

void StressDriver::printStat()
{
	using namespace std;
	cout << endl << "Stats:" << endl;
	cout << "packetsSent:" << packetsSent  << endl;
	cout << " routingPacketSent:" << routingPacketSent<< endl;
	cout << " segPacketSent:" << segPacketSent << endl;
	cout << " ackPackeSent:" << ackPackeSent << endl;
	cout << "packetsRecieved:" << packetsRecieved << endl;
	cout << " routingPacketReceived:" << routingPacketReceived << endl;
	cout << " segPacketReceived:" << segPacketReceived << endl;
	cout << " ackPacketReceived:" << ackPacketReceived << endl;
	cout << "messagesSent: " << messagesSent << endl;
	cout << "messagesReceived: " << messagesReceived << endl;
	
	cout << endl;
}


void StressDriver::addEventToSimulator(simulator::Event* e)
{
	using namespace std;
	packetsSent++;
	PacketHeader* p = (PacketHeader*)(e->getPacket().data());
	if (p->tos == TOS_ROUTING)
		routingPacketSent++;
	else if (p->tos == TOS_SEGMENT)
	{
		TransportLayerHeader* t = (TransportLayerHeader*)(e->getPacket().data() + sizeof(PacketHeader));
		if (t->type == TTYPE_ACK)	
			ackPackeSent++;
		else
			segPacketSent++;
	}
}

void StressDriver::recieveEventAtNode(simulator::Event* e)
{
	packetsRecieved++;
	PacketHeader* p = (PacketHeader*)(e->getPacket().data());
	if (p->tos == TOS_ROUTING)
		routingPacketReceived++;
	else if (p->tos == TOS_SEGMENT)
	{
		TransportLayerHeader* t = (TransportLayerHeader*)(e->getPacket().data() + sizeof(PacketHeader));
		if (t->type == TTYPE_ACK)	
			ackPacketReceived++;
		else
			segPacketReceived++;
	}	
}

StressDriver::StressDriver(int nodes, int world)
{
	nrNodes = nodes;
	worldType = world;

	packetsSent = 0;
	packetsRecieved = 0;
	routingPacketSent = 0;
	ackPackeSent = 0;
	segPacketSent = 0;
	routingPacketReceived = 0;
	ackPacketReceived = 0;
	segPacketReceived = 0;
	
	messagesSent = 0;
	messagesReceived = 0;
}
